閉包這個題目,真的有點難...
不過還是讓我們來嘗試看看吧!!
A closure is the combination of
a function
andthe lexical environment
within which that function was declared. i.e, It is an inner function that has access to the outer or enclosing function’s variables. The closure has three scope chains
- Own scope where variables defined between its curly brackets
- Outer function’s variables
- Global variables
閉包是指一個函式及此函式宣告的語彙環境的組合。亦即閉包是一個可以存取外部函式
的變數的內部函式
。閉包有三個範疇鍊(作用域):
Scope is the accessibility of variables, functions, and objects in some particular part of your code during runtime. In other words, scope determines the visibility of variables and other resources in areas of your code.
作用域描述了在程式的執行階段中,一段特定的程式碼中的變數、函式、或者物件,是否可被存取。換句話說,作用域決定了在特定的程式區塊中,變數或者資源是否能被抓到(caught)。
無法被抓到就會出現Uncaught ReferenceError: _ is not defined (´A` )有沒有很熟悉
以函式為例,在其中生成的變數,只能在其中生存,離開這個環境後就會被釋放(從外部存取不到)。
const saySomethingTo = (name) => {
let message = `Good night,`
console.log(`${message} ${name}`)
}
saySomethingTo('Leo') // "Good night, Leo"
console.log(message) // Uncaught ReferenceError: message is not defined
而閉包就是利用作用域這個特性,來達成一個效果:
是不是還是一頭霧水呢(ಠ益ಠ)?先讓我們來看看下面的範例吧!
// 1. 原本的函式
var leftFood = 3000
var income = 0
function sellFood(n) {
leftFood -= n
income += n*10
}
sellFood(100)
console.log(leftFood) // 2900,賣掉100個食物,剩下2900個
console.log(income) // 1000,一個食物10元,總收入1000元
leftFood -= 200
console.log(leftFood) // 2700,被偷走200個食物
console.log(income) // 1000,因為是被偷走的,所以收入沒增加
// 2. 運用閉包的特性改寫
function restaurant() {
var leftFood = 3000
var income = 0
return {
sellFood: (n) => {
leftFood -= n
income += n*10
console.log(leftFood)
console.log(income)
}
}
}
var myRestaurant = restaurant()
myRestaurant.sellFood(100) // 2900, 1000 賣100個食物,總收入1000元
myRestaurant.sellFood(100) // 2800, 2000 再賣100個食物,總收入2000元
leftFood -= 200 // Uncaught ReferenceError: leftFood is not defined 偷不到食物了!
在第一個函式中,我們可以透過執行sellFood(n)
來讓變數依照我們的規則做改變,在此範例中,就是:賣出食物,就會有收入。但是因為變數裸露在外,所以是可以直接對其做修改的!(leftFood -= 200
)若真的發生這樣的事,餐廳的帳就會對不起來啦ˊ_ゝˋ
而第二個函式,我們把變數藏在restaurant()
裡面,並且令其回傳一個「物件」,內含一個key
是sellFood
的函式。如此一來,若要在外部存取這個物件運用到的變數,只要透過restaurant()去執行它所回傳的這個函式即可。
var myRestaurant = restaurant()
myRestaurant.sellFood(100)
若試圖從外部直接存取leftFood
,也僅僅會得到Uncaught ReferenceError而已。
這樣食物就不會被偷走啦~~
今天用到的範例有物件的概念,明天開始我們來看看「Object」在JavaScript之中是怎麼樣的一回事吧!和function比較直接相關的面試問題,就先分享到這邊囉~~
若有什麼錯誤,還請不吝留言指正~~謝謝各位願意來看我的文章(被荼毒的話真的很抱歉。゚ヽ(゚´Д`)ノ゚。)
因為閉包這個概念真的太難解釋了,所以我同時參考了國內幾個大大的文章,其中這一篇寫得非常明白,連身為菜雞的我也能看得懂幾成。推薦大家可以把它看完:)